package cn.easyplatform.studio.cmd.link;

import cn.easyplatform.lang.Strings;
import cn.easyplatform.studio.interceptor.Command;
import cn.easyplatform.studio.interceptor.CommandContext;
import cn.easyplatform.studio.utils.GlobalVariableService;
import cn.easyplatform.studio.utils.StringUtil;
import cn.easyplatform.studio.vos.LinkVo;
import cn.easyplatform.studio.vos.TypeLinkVo;
import cn.easyplatform.type.EntityType;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class CheckLinkCmd implements Command<CheckLinkCmd.CheckResultStatus> {
    public enum CheckStatus {
        CHECK_STATUS_ADD, CHECK_STATUS_UPDATE_ENTITY, CHECK_STATUS_MOVE
    }
    public enum CheckResultStatus {
        CHECK_SUCCESS, CHECK_ERROR_NO_EXIT, CHECK_ERROR_PARENT_TASK, CHECK_ERROR_CHANGED,
        CHECK_ERROR_DOUBLE, CHECK_ERROR_OTHER, CHECK_ERROR_PATH_DOUBLE
    }
    private LinkVo parentVo;
    private LinkVo originalVo;
    private LinkVo toMoveVo;
    private LinkVo fromVo;
    private List<LinkVo> voList;
    private String rootEntityId;
    private CheckStatus status;
    private LinkVo addVo;
    //private List<TypeLinkVo> typeLinkVos;
    /*添加*/
    public CheckLinkCmd(LinkVo parentVo, String rootEntityId, List<LinkVo> voList, LinkVo addVo)
    {
        this.rootEntityId = rootEntityId;
        this.voList = voList;
        this.addVo = addVo;
        //this.typeLinkVos = NavbarControllerImpl.getDataTypeLinkVoList();
        this.status = CheckStatus.CHECK_STATUS_ADD;
        this.parentVo = parentVo;
    }
    /*修改*/
    public CheckLinkCmd(LinkVo parentVo, List<LinkVo> voList)
    {
        this.voList = voList;
        this.status = CheckStatus.CHECK_STATUS_UPDATE_ENTITY;
        this.originalVo = parentVo;

    }
    /*移动*/
    public CheckLinkCmd(LinkVo originalVo, LinkVo toMoveVo, LinkVo fromVo, List<LinkVo> voList)
    {
        this.originalVo = originalVo;
        this.fromVo = fromVo;
        this.voList = voList;
        this.status = CheckStatus.CHECK_STATUS_MOVE;
        this.toMoveVo = toMoveVo;
    }
    @Override
    public CheckResultStatus execute(CommandContext cc) {
        if (status.equals(CheckStatus.CHECK_STATUS_ADD)) {
            //判断link合法
            LinkVo resultVo = checkedEntity(parentVo.getEntityId());
            //判断task link合法
            boolean isDouble = getDoubleTaskEntity(rootEntityId, addVo.getEntityId());
            if (resultVo == null)
                return CheckResultStatus.CHECK_ERROR_NO_EXIT;
            else if (EntityType.TASK.getName().equals(resultVo.getEntityType()) &&
                    resultVo.getEntityId().equals(rootEntityId) == false)
                return CheckResultStatus.CHECK_ERROR_PARENT_TASK;
            else if (parentVo.isCanAdd() == false)
                return CheckResultStatus.CHECK_ERROR_PATH_DOUBLE;
            else if (addVo.getEntityId().equals(parentVo.getEntityId()))
                return CheckResultStatus.CHECK_ERROR_DOUBLE;
            else if (addVo.getEntityId().equals(rootEntityId))
                return CheckResultStatus.CHECK_ERROR_DOUBLE;
            else
                return CheckResultStatus.CHECK_SUCCESS;
        } else if (status.equals(CheckStatus.CHECK_STATUS_UPDATE_ENTITY)) {
            LinkVo resultVo = checkedEntity(originalVo.getEntityId());
            return getErrorWithUpdate(originalVo, resultVo);
        } else if (status.equals(CheckStatus.CHECK_STATUS_MOVE)) {
            LinkVo resultVo = checkedEntity(originalVo.getEntityId());
            CheckResultStatus status = getErrorWithUpdate(originalVo, resultVo);
            LinkVo fromResultVo = checkedEntity(fromVo.getEntityId());
            CheckResultStatus fromStatus = getErrorWithUpdate(fromVo, fromResultVo);
            LinkVo toResultVo = checkedEntity(toMoveVo.getEntityId());
            CheckResultStatus toStatus = getErrorWithUpdate(toMoveVo, toResultVo);
            if (CheckResultStatus.CHECK_SUCCESS.equals(status) == false)
                return status;
            else if (CheckResultStatus.CHECK_SUCCESS.equals(fromStatus) == false)
                return fromStatus;
            else if (CheckResultStatus.CHECK_SUCCESS.equals(toStatus) == false)
                return toStatus;
            else if (toResultVo.isCanAdd() == false)
                return CheckResultStatus.CHECK_ERROR_PATH_DOUBLE;
            else if (resultVo.getEntityId().equals(toResultVo.getEntityId()))
                return CheckResultStatus.CHECK_ERROR_DOUBLE;
            /*else if (getDoubleEntityList(toMoveVo, originalVo, voList) == true)
                return CheckResultStatus.CHECK_ERROR_DOUBLE;*/
            else
                return CheckResultStatus.CHECK_SUCCESS;
        }
        return CheckResultStatus.CHECK_ERROR_OTHER;
    }

    private LinkVo checkedEntity(String entityId)
    {
        return searchEntityID(entityId, voList);
    }

    private LinkVo searchEntityID(String entityID, List<LinkVo> list) {
        LinkVo searchLinkVo= null;
        for (LinkVo linkVo: list) {
            if (linkVo.getEntityId().equals(entityID)) {
                searchLinkVo = linkVo;
            }

            if(null != linkVo.getChildrenList() && linkVo.getChildrenList().size() > 0) {
                LinkVo childrenLinkVo= searchEntityID(entityID, linkVo.getChildrenList());
                if (childrenLinkVo != null)
                    return childrenLinkVo;
            }
        }
        return searchLinkVo;
    }

    private CheckResultStatus getErrorWithUpdate(LinkVo oriVo, LinkVo resultVo)
    {
        if (resultVo == null)
            return CheckResultStatus.CHECK_ERROR_NO_EXIT;

        boolean isChange = false;
        if (StringUtil.isChangeString(oriVo.getEntityId(), resultVo.getEntityId()))
            isChange = true;
        else if (StringUtil.isChangeString(oriVo.getEntityType(), resultVo.getEntityType()))
            isChange = true;
        else if (StringUtil.isChangeString(oriVo.getEntitySubType(), resultVo.getEntitySubType()))
            isChange = true;
        else if (StringUtil.isChangeString(oriVo.getEntityName(), resultVo.getEntityName()))
            isChange = true;
        else if (StringUtil.isChangeString(oriVo.getEntityDesp(), resultVo.getEntityDesp()))
            isChange = true;
        else if (StringUtil.isChangeString(oriVo.getStatus(), resultVo.getStatus()))
            isChange = true;
        else if (StringUtil.isChangeString(oriVo.getChildrenEntityId(), resultVo.getChildrenEntityId()))
            isChange = true;

        if (isChange == true)
            return CheckResultStatus.CHECK_ERROR_CHANGED;
        else
            return CheckResultStatus.CHECK_SUCCESS;
    }

    /**
     * 判断添加节点列表的每一个元素是否存在于父节点到根节点路径中
     * @param parentVo 父节点
     * @param moveVo 移动节点
     * @param list 树结构所有数据
     * @return
     */
    private Boolean getDoubleEntityList(LinkVo parentVo, LinkVo moveVo, List<LinkVo> list) {
        List<LinkVo> linkVos = allEntity(list.get(0), new ArrayList<LinkVo>());
        List<LinkVo> linkTree = new ArrayList<>();
        linkTree.add(parentVo);
        linkTree = searchEntity(parentVo, linkVos, linkTree);
        List<LinkVo> moveTree = allEntity(moveVo, new ArrayList<LinkVo>());
        for (LinkVo linkVo: linkTree) {
            for (LinkVo moveLinkVo: moveTree) {
                if (linkVo.getEntityId().equals(moveLinkVo.getEntityId())) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 判断添加节点是否存在于父节点到根节点路径中
     * @param parentVo 父节点
     * @param addEntityId 添加节点的ID
     * @param list 树结构所有数据
     * @return
     */
    private Boolean getDoubleEntity(LinkVo parentVo, String addEntityId, List<LinkVo> list) {
        List<LinkVo> linkVos = allEntity(list.get(0), new ArrayList<LinkVo>());
        List<LinkVo> linkTree = new ArrayList<>();
        linkTree.add(parentVo);
        linkTree = searchEntity(parentVo, linkVos, linkTree);
        for (LinkVo linkVo: linkTree) {
            if (linkVo.getEntityId().equals(addEntityId)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 把树形结构转成表结构
     * @param linkVo 树形结构
     * @param result 表结构
     * @return 表结构
     */
    private List<LinkVo> allEntity(LinkVo linkVo, List<LinkVo> result) {
        if (linkVo != null)
            result.add(linkVo);
        for (LinkVo vo: linkVo.getChildrenList()) {
            allEntity(vo, result);
        }
        return result;
    }

    /**
     * 在表结构中搜索需要的参数到根的路径的所有节点
     * @param searchVo 需要搜索的节点
     * @param content 表结构
     * @param result 储存所有节点
     * @return 所有节点
     */
    private List<LinkVo> searchEntity(LinkVo searchVo, List<LinkVo> content, List<LinkVo> result) {
        for (LinkVo vo:content) {
            if (vo.getChildrenList().contains(searchVo)) {
                result.add(vo);
                searchEntity(vo, content, result);
            }
        }
        return result;
    }

    private Boolean getDoubleTaskEntity(String parentEntityId, String addTaskEntityId) {
        List<List<TypeLinkVo>> linkTree = new ArrayList<>();
        //搜索父亲节点第一级
        for (TypeLinkVo linkVo: GlobalVariableService.getInstance().getDataTypeLinkVoList()) {
            List<String> childrenEntityIdList = new ArrayList<>();
            if (Strings.isBlank(linkVo.getChildrenEntityId()) == false)
                childrenEntityIdList = Arrays.asList(linkVo.getChildrenEntityId().split(","));
            if (childrenEntityIdList.size() > 0) {
                if (childrenEntityIdList.contains(parentEntityId)) {
                    List<TypeLinkVo> linkVoList = new ArrayList<>();
                    linkVoList.add(linkVo);
                    linkTree.add(linkVoList);
                }
            }
        }
        //搜索所有有关这个节点的路径
        if (linkTree.size() > 0) {
            for (List<TypeLinkVo> typeLinkVos: linkTree) {
                searchTaskEntity(typeLinkVos.get(0), typeLinkVos);
            }
        }
        for (List<TypeLinkVo> typeLinkVos: linkTree) {
            for (TypeLinkVo typeLinkVo: typeLinkVos) {
                if (typeLinkVo.getEntityId().equals(addTaskEntityId)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 搜索task关系表中参数到根的路径的所有节点
     * @param searchVo 需要搜索的节点
     * @param result 储存所有节点
     * @return 所有节点
     */
    private List<TypeLinkVo> searchTaskEntity(TypeLinkVo searchVo, List<TypeLinkVo> result) {
        for (TypeLinkVo vo:GlobalVariableService.getInstance().getDataTypeLinkVoList()) {
            if (vo.getChildrenList().contains(searchVo)) {
                result.add(vo);
                searchTaskEntity(vo, result);
            }
        }
        return result;
    }
}
